#include "pattern.hh"

#include <string>
#include <vector>
#include <fstream>

Pattern::Pattern(std::ifstream& infile) : 
    _matrix{}
{
    std::string line;
    while (std::getline(infile, line))
    {
        if (line.empty()) break;
        this->_matrix.emplace_back(std::move(line));
    }
}

std::size_t Pattern::mirrorsPosition() const
{
    std::optional<std::size_t> rowPos {this->rowMirrorsPosition()};
    if (rowPos.has_value()) {
        return 100 * rowPos.value();
    }
    
    std::optional<std::size_t> colPos {this->colMirrorsPosition()};
    if (colPos.has_value()) {
        return colPos.value();
    }

    std::exit(1);
}

std::optional<std::size_t> Pattern::rowMirrorsPosition() const 
{
    // Find two same colosed rows 
    for (std::size_t r = 0; r < this->_matrix.size() - 1; ++r)
    {
        if (this->_matrix[r] == this->_matrix[r + 1]) 
        {
            if (r == 0 || r == this->_matrix.size() - 2) 
                return std::optional<std::size_t>{r + 1};

            std::size_t front {r - 1};
            std::size_t back {r + 2};

            bool isMirror {true};
            while (true) 
            {
                if (this->_matrix[front] != this->_matrix[back])
                {
                    isMirror = false;
                    break;
                }
                // Check next
                if (front == 0 || back == this->_matrix.size() - 1)
                    break;
                front -= 1;
                back  += 1;
            }

            if (isMirror) return std::optional<std::size_t>{r + 1};
        }
    }

    return std::optional<std::size_t>{};
}

std::optional<std::size_t> Pattern::colMirrorsPosition() const 
{
    std::size_t colSize {this->_matrix.front().size()};
    std::size_t rowSize {this->_matrix.size()};

    for (std::size_t c = 0; c < colSize - 1; ++c)
    {
        if (this->compareColumns(c, c + 1))
        {
            if (c == 0 || c == colSize - 2) 
                return std::optional<std::size_t>{c + 1};
            
            std::size_t left {c - 1};
            std::size_t right {c + 2};

            bool isMirror {true};
            while (true) 
            {
                if (!this->compareColumns(left, right))
                {
                    isMirror = false;
                    break;
                }

                if (left == 0 || right == colSize - 1)
                    break;
                
                left -= 1;
                right += 1;
            }
            if (isMirror) return std::optional<std::size_t>{c + 1};
        }
    }

    return std::optional<std::size_t>{};
}

bool Pattern::compareColumns(std::size_t col1, std::size_t col2) const
{
    for (std::size_t row = 0; row < this->_matrix.size(); ++row) 
    {
        if (this->_matrix[row][col1] != this->_matrix[row][col2])
            return false;
    }
    return true;
}